#include "SQLUtils.h"
#include "../utils/instanceof.h"
#include "../utils/Utils.h"
#include "../utils/StringUtils.h"
#include "../utils/FnvHash.h"
#include "../utils/log.h"
#include "parser/SQLParserUtils.h"
#include "../Exception/IllegalArgumentException.h"
#include "ast/statement/SQLJoinTableSource.h"
#include "ast/statement/SQLUnionQuery.h"
#include "ast/statement/SQLCreateTableStatement.h"
#include "ast/statement/SQLSelectItem.h"
#include "ast/statement/SQLSelectStatement.h"
#include "ast/statement/SQLDumpStatement.h"
#include "ast/statement/SQLSetStatement.h"
#include "ast/SQLStatementImpl.h"
#include "repository/SchemaRepository.h"
#include "visitor/SchemaStatVisitor.h"
#include "visitor/SQLASTOutputVisitor.h"
#include "dialect/mysql/visitor/MySqlSchemaStatVisitor.h"
#include "dialect/mysql/ast/clause/MySqlSelectIntoStatement.h"
#include "dialect/mysql/ast/statement/MySqlInsertStatement.h"
#include "dialect/mysql/visitor/MySqlOutputVisitor.h"
#include "dialect/oracle/visitor/OracleOutputVisitor.h"

// class TimeZoneVisitor : virtual public SQLASTVisitorAdapter {
//     TimeZone from;
//     TimeZone to;

//     TimeZoneVisitor(TimeZone from, TimeZone to) {
//         this->from = from;
//         this->to = to;
//     }

//     BOOL_ptr visit(SQLTimestampExpr x) {
//         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

//         string_ptr  newTime = format->format(x->getDate(from));

//         x->setLiteral(newTime);

//         return BOOL::TRUE;
//     }

// };
SQLParserFeature_list_ptr SQLUtils::FORMAT_DEFAULT_FEATURES = std::make_shared<std::list<SQLParserFeature_ptr>>();

FormatOption_ptr SQLUtils::DEFAULT_FORMAT_OPTION = FormatOption_ptr(new FormatOption(BOOL::TRUE, BOOL::TRUE));
FormatOption_ptr SQLUtils::DEFAULT_LCASE_FORMAT_OPTION = FormatOption_ptr(new FormatOption(BOOL::FALSE, BOOL::TRUE));
BOOL_ptr SQLUtils::__init = SQLUtils::init();
BOOL_ptr SQLUtils::init()
{
  // LOG_INFO << SQLParserFeature::KeepComments.mask << ":" << SQLParserFeature::KeepComments.toString();
  // LOG_INFO << SQLParserFeature::EnableSQLBinaryOpExprGroup.mask << ":" << SQLParserFeature::EnableSQLBinaryOpExprGroup.toString();
  SQLUtils::FORMAT_DEFAULT_FEATURES->push_back(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::KeepComments)));
  SQLUtils::FORMAT_DEFAULT_FEATURES->push_back(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::EnableSQLBinaryOpExprGroup)));
}

FormatOption::FormatOption()
{
  lis_VisitorFeature = std::make_shared<std::list<VisitorFeature_ptr>>();

  lis_VisitorFeature->push_back(std::make_shared<VisitorFeature>(VisitorFeature::OutputUCase));
  lis_VisitorFeature->push_back(std::make_shared<VisitorFeature>(VisitorFeature::OutputPrettyFormat));
  features = VisitorFeature::of(lis_VisitorFeature);
}

FormatOption::FormatOption(VisitorFeature_list_ptr features)
{
  lis_VisitorFeature = std::make_shared<std::list<VisitorFeature_ptr>>();
  this->features = VisitorFeature::of(features);
}

FormatOption::FormatOption(BOOL_ptr ucase)
{
  FormatOption(ucase, BOOL::TRUE);
}

FormatOption::FormatOption(BOOL_ptr ucase, BOOL_ptr prettyFormat)
{
  FormatOption(ucase, prettyFormat, BOOL::FALSE);
}

FormatOption::FormatOption(BOOL_ptr ucase, BOOL_ptr prettyFormat, BOOL_ptr parameterized)
{
  lis_VisitorFeature = std::make_shared<std::list<VisitorFeature_ptr>>();
  this->features = VisitorFeature::config(this->features, std::make_shared<VisitorFeature>(VisitorFeature::OutputUCase), ucase);
  this->features = VisitorFeature::config(this->features, std::make_shared<VisitorFeature>(VisitorFeature::OutputPrettyFormat), prettyFormat);
  this->features = VisitorFeature::config(this->features, std::make_shared<VisitorFeature>(VisitorFeature::OutputParameterized), parameterized);
}

BOOL_ptr FormatOption::isDesensitize()
{
  return isEnabled(std::make_shared<VisitorFeature>(VisitorFeature::OutputDesensitize));
}

void FormatOption::setDesensitize(BOOL_ptr val)
{
  config(std::make_shared<VisitorFeature>(VisitorFeature::OutputDesensitize), val);
}

BOOL_ptr FormatOption::isUppCase()
{
  return isEnabled(std::make_shared<VisitorFeature>(VisitorFeature::OutputUCase));
}

void FormatOption::setUppCase(BOOL_ptr val)
{
  config(std::make_shared<VisitorFeature>(VisitorFeature::OutputUCase), val);
}

BOOL_ptr FormatOption::isPrettyFormat()
{
  return isEnabled(std::make_shared<VisitorFeature>(VisitorFeature::OutputPrettyFormat));
}

void FormatOption::setPrettyFormat(BOOL_ptr prettyFormat)
{
  config(std::make_shared<VisitorFeature>(VisitorFeature::OutputPrettyFormat), prettyFormat);
}

BOOL_ptr FormatOption::isParameterized()
{
  return isEnabled(std::make_shared<VisitorFeature>(VisitorFeature::OutputParameterized));
}

void FormatOption::setParameterized(BOOL_ptr parameterized)
{
  config(std::make_shared<VisitorFeature>(VisitorFeature::OutputParameterized), parameterized);
}

void FormatOption::config(VisitorFeature_ptr feature, BOOL_ptr state)
{
  features = VisitorFeature::config(features, feature, state);
}

BOOL_ptr FormatOption::isEnabled(VisitorFeature_ptr feature)
{
  // return VisitorFeature::isEnabled(this->features, feature);
  return BOOL::TRUE;
}

string_ptr SQLUtils::toSQLString(SQLObject_ptr sqlObject, DbType_ptr dbType)
{
  VisitorFeature_list_ptr tmp = std::make_shared<std::list<VisitorFeature_ptr>>();
  return toSQLString(sqlObject, dbType, (FormatOption_ptr) nullptr, tmp);
}

string_ptr SQLUtils::toSQLString(Object_ptr sqlObject, DbType_ptr dbType)
{
  VisitorFeature_list_ptr tmp = std::make_shared<std::list<VisitorFeature_ptr>>();
  return toSQLString(std::dynamic_pointer_cast<SQLObject>(sqlObject), dbType, (FormatOption_ptr) nullptr, tmp);
}

string_ptr SQLUtils::toSQLString(SQLObject_ptr sqlObject, DbType_ptr dbType, FormatOption_ptr option)
{
  VisitorFeature_list_ptr tmp = std::make_shared<std::list<VisitorFeature_ptr>>();
  return toSQLString(sqlObject, dbType, option, tmp);
}

string_ptr SQLUtils::toSQLString(SQLObject_ptr sqlObject,
                                 DbType_ptr dbType,
                                 FormatOption_ptr option,
                                 VisitorFeature_list_ptr features)
{
  std::stringstream out;
  SQLASTOutputVisitor_ptr visitor = createOutputVisitor(&out, dbType);

  if (option == nullptr)
  {
    option = DEFAULT_FORMAT_OPTION;
  }

  // visitor->setUppCase(option->isUppCase());
  // visitor->setPrettyFormat(option->isPrettyFormat());
  // visitor->setParameterized(option->isParameterized());

  int featuresValue = option->features;
  if (!features->empty())
  {
    for (VisitorFeature_ptr feature : *features)
    {
      // visitor->config(feature, BOOL::TRUE);
      // featuresValue |= feature->mask;
    }
  }

  // visitor->setFeatures(featuresValue);

  // sqlObject->accept(visitor);

  // string_ptr  sql = out;
  return make_string_ptr(out.str());
}

string_ptr SQLUtils::toSQLString(SQLStatementImpl_ptr sqlObject,
                                 DbType_ptr dbType,
                                 FormatOption_ptr option,
                                 VisitorFeature_list_ptr features)
{
  std::stringstream out;
  SQLASTOutputVisitor_ptr visitor = createOutputVisitor(&out, dbType);

  if (option == nullptr)
  {
    option = DEFAULT_FORMAT_OPTION;
  }

  // visitor->setUppCase(option->isUppCase());
  // visitor->setPrettyFormat(option->isPrettyFormat());
  // visitor->setParameterized(option->isParameterized());

  int featuresValue = option->features;
  if (!features->empty())
  {
    for (VisitorFeature_ptr feature : *features)
    {
      // visitor->config(feature, BOOL::TRUE);
      // featuresValue |= feature->mask;
    }
  }

  // visitor->setFeatures(featuresValue);

  // sqlObject->accept(visitor);

  string_ptr sql = make_string_ptr(out.str());
  return sql;
}

string_ptr SQLUtils::toSQLString(SQLObject_ptr obj)
{
  if (instanceof <SQLObject, SQLStatement>(obj))
  {
    SQLStatement_ptr stmt = std::dynamic_pointer_cast<SQLStatement>(obj);
    return toSQLString(std::dynamic_pointer_cast<SQLObject>(stmt), stmt->getDbType());
  }

  // if (instanceof <SQLObject, MySqlObject>(obj))
  // {
  //   return toMySqlString(dynamic_cast<SQLObject_ptr >(obj));
  // }

  string_ptr out;
  // obj->accept(new SQLASTOutputVisitor(out));

  string_ptr sql = out;
  return sql;
}

string_ptr SQLUtils::toOdpsString(SQLObject_ptr sqlObject)
{
  return toOdpsString(sqlObject, nullptr);
}

string_ptr SQLUtils::toHiveString(SQLObject_ptr sqlObject)
{
  return toSQLString(sqlObject, DbType_ptr(new DbType(&DbType::odps)));
}

string_ptr SQLUtils::toOdpsString(SQLObject_ptr sqlObject, FormatOption_ptr option)
{
  return toSQLString(sqlObject, DbType_ptr(new DbType(&DbType::odps)), option);
}

string_ptr SQLUtils::toAntsparkString(SQLObject_ptr sqlObject)
{
  return toAntsparkString(sqlObject, nullptr);
}

string_ptr SQLUtils::toAntsparkString(SQLObject_ptr sqlObject, FormatOption_ptr option)
{
  return toSQLString(sqlObject, DbType_ptr(new DbType(&DbType::antspark)), option);
}

string_ptr SQLUtils::toMySqlString(SQLObject_ptr sqlObject)
{
  return toMySqlString(sqlObject, (FormatOption_ptr) nullptr);
}

string_ptr SQLUtils::toMySqlStringIfNotNull(SQLObject_ptr sqlObject, string_ptr defaultStr)
{
  if (sqlObject == nullptr)
  {
    return defaultStr;
  }

  return toMySqlString(sqlObject, (FormatOption_ptr) nullptr);
}

string_ptr SQLUtils::toMySqlString(SQLObject_ptr sqlObject, VisitorFeature_list_ptr features)
{
  return toMySqlString(sqlObject, FormatOption_ptr(new FormatOption(features)));
}

string_ptr SQLUtils::toNormalizeMysqlString(SQLObject_ptr sqlObject)
{
  if (sqlObject != nullptr)
  {
    return SQLUtils::normalize(toSQLString(sqlObject, DbType_ptr(new DbType(&DbType::mysql))));
  }
  return nullptr;
}

string_ptr SQLUtils::toMySqlString(SQLObject_ptr sqlObject, FormatOption_ptr option)
{
  return toSQLString(sqlObject, DbType_ptr(new DbType(&DbType::mysql)), option);
}

SQLExpr_ptr SQLUtils::toMySqlExpr(string_ptr sql)
{
  return toSQLExpr(sql, DbType_ptr(new DbType(&DbType::mysql)));
}

string_ptr SQLUtils::formatMySql(string_ptr sql)
{
  return format(sql, DbType_ptr(new DbType(&DbType::mysql)));
}

string_ptr SQLUtils::formatMySql(string_ptr sql, FormatOption_ptr option)
{
  return format(sql, DbType_ptr(new DbType(&DbType::mysql)), option);
}

string_ptr SQLUtils::formatOracle(string_ptr sql)
{
  return format(sql, DbType_ptr(new DbType(&DbType::oracle)));
}

string_ptr SQLUtils::formatOracle(string_ptr sql, FormatOption_ptr option)
{
  return format(sql, DbType_ptr(new DbType(&DbType::oracle)), option);
}

string_ptr SQLUtils::formatOdps(string_ptr sql)
{
  return format(sql, DbType_ptr(new DbType(&DbType::odps)));
}

string_ptr SQLUtils::formatPresto(string_ptr sql)
{
  return formatPresto(sql, nullptr);
}

string_ptr SQLUtils::formatPresto(string_ptr sql, FormatOption_ptr option)
{
  // std::list<SQLParserFeature *> features = {&SQLParserFeature::KeepComments,
  //                                           &SQLParserFeature::EnableSQLBinaryOpExprGroup,
  //                                           &SQLParserFeature::KeepNameQuotes};
  SQLParserFeature_list_ptr features = std::make_shared<std::list<SQLParserFeature_ptr>>();
  features->push_back(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::KeepComments)));
  features->push_back(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::EnableSQLBinaryOpExprGroup)));
  features->push_back(SQLParserFeature_ptr(new SQLParserFeature(&SQLParserFeature::KeepNameQuotes)));
  Object_list_ptr tmp = std::make_shared<std::list<Object_ptr>>();
  return format(sql, DbType_ptr(new DbType(&DbType::mysql)), tmp, option, features);
}

string_ptr SQLUtils::formatHive(string_ptr sql)
{
  return format(sql, DbType_ptr(new DbType(&DbType::hive)));
}

string_ptr SQLUtils::formatOdps(string_ptr sql, FormatOption_ptr option)
{
  return format(sql, DbType_ptr(new DbType(&DbType::odps)), option);
}

string_ptr SQLUtils::formatHive(string_ptr sql, FormatOption_ptr option)
{
  return format(sql, DbType_ptr(new DbType(&DbType::hive)), option);
}

string_ptr SQLUtils::formatSQLServer(string_ptr sql)
{
  return format(sql, DbType_ptr(new DbType(&DbType::sqlserver)));
}

string_ptr SQLUtils::toOracleString(SQLObject_ptr sqlObject)
{
  return toOracleString(sqlObject, nullptr);
}

string_ptr SQLUtils::toOracleString(SQLObject_ptr sqlObject, FormatOption_ptr option)
{
  return toSQLString(sqlObject, DbType_ptr(new DbType(&DbType::oracle)), option);
}

string_ptr SQLUtils::toPGString(SQLObject_ptr sqlObject)
{
  return toPGString(sqlObject, nullptr);
}

string_ptr SQLUtils::toPGString(SQLObject_ptr sqlObject, FormatOption_ptr option)
{
  return toSQLString(sqlObject, DbType_ptr(new DbType(&DbType::postgresql)), option);
}

string_ptr SQLUtils::toDB2String(SQLObject_ptr sqlObject)
{
  return toDB2String(sqlObject, nullptr);
}

string_ptr SQLUtils::toDB2String(SQLObject_ptr sqlObject, FormatOption_ptr option)
{
  return toSQLString(sqlObject, DbType_ptr(new DbType(&DbType::db2)), option);
}

string_ptr SQLUtils::toSQLServerString(SQLObject_ptr sqlObject)
{
  return toSQLServerString(sqlObject, nullptr);
}

string_ptr SQLUtils::toSQLServerString(SQLObject_ptr sqlObject, FormatOption_ptr option)
{
  return toSQLString(sqlObject, DbType_ptr(new DbType(&DbType::sqlserver)), option);
}

string_ptr SQLUtils::formatPGSql(string_ptr sql, FormatOption_ptr option)
{
  return format(sql, DbType_ptr(new DbType(&DbType::postgresql)), option);
}

SQLExpr_ptr SQLUtils::toSQLExpr(string_ptr sql, DbType_ptr dbType)
{
  SQLExprParser_ptr parser = SQLParserUtils::createExprParser(sql, dbType);
  SQLExpr_ptr expr = parser->getExpr();

  if (*(parser->getLexer())->token() != Token::XEOF)
  {
    throw new ParserException(make_string_ptr("illegal sql expr : " + *sql + ", " + encode_util::UnicodeToUTF8(parser->getLexer()->info()).c_str()));
  }

  return expr;
}

SQLSelectOrderByItem_ptr SQLUtils::toOrderByItem(string_ptr sql, DbType_ptr dbType)
{
  SQLExprParser_ptr parser = SQLParserUtils::createExprParser(sql, dbType);
  SQLSelectOrderByItem_ptr orderByItem = parser->parseSelectOrderByItem();

  if (*parser->getLexer()->token() != Token::XEOF)
  {
    throw new ParserException(make_string_ptr("illegal sql expr : " + *sql + ", " + encode_util::UnicodeToUTF8(parser->getLexer()->info()).c_str()));
  }

  return orderByItem;
}

// SQLUpdateSetItem* SQLUtils::toUpdateSetItem(string_ptr  sql, DbType_ptr   dbType)
// {
//   SQLExprParser* parser = SQLParserUtils::createExprParser(sql, dbType);
//   SQLUpdateSetItem* updateSetItem = parser->parseUpdateSetItem();

//   if (*parser->getLexer()->token() != Token::XEOF)
//   {
//     throw new ParserException("illegal sql expr : " + sql + ", " + parser->getLexer()->info());
//   }

//   return updateSetItem;
// }

SQLSelectItem_ptr SQLUtils::toSelectItem(string_ptr sql, DbType_ptr dbType)
{
  SQLExprParser_ptr parser = SQLParserUtils::createExprParser(sql, dbType);
  SQLSelectItem_ptr selectItem = parser->parseSelectItem();

  if (*parser->getLexer()->token() != Token::XEOF)
  {
    throw new ParserException(make_string_ptr("illegal sql expr : " + *sql + ", " + encode_util::UnicodeToUTF8(parser->getLexer()->info()).c_str()));
  }

  return selectItem;
}

SQLStatement_list_ptr SQLUtils::toStatementList(string_ptr sql, DbType_ptr dbType)
{
  SQLStatementParser_ptr parser = SQLParserUtils::createSQLStatementParser(sql, dbType);
  return parser->parseStatementList();
}

SQLExpr_ptr SQLUtils::toSQLExpr(string_ptr sql)
{
  return toSQLExpr(sql, DbType_ptr(new DbType(&DbType::other)));
}

// string_ptr  SQLUtils::format(string_ptr  sql, string_ptr  dbType)
// {
//   return format(sql, &DbType::valueOf(dbType));
// }

string_ptr SQLUtils::format(string_ptr sql, DbType_ptr dbType)
{
  Object_list_ptr tmp = std::make_shared<std::list<Object_ptr>>();
  return format(sql, dbType, tmp, (FormatOption_ptr) nullptr);
}

string_ptr SQLUtils::format(string_ptr sql, DbType_ptr dbType, FormatOption_ptr option)
{
  Object_list_ptr tmp = std::make_shared<std::list<Object_ptr>>();
  return format(sql, dbType, tmp, option);
}

string_ptr SQLUtils::format(string_ptr sql, DbType_ptr dbType, Object_list_ptr parameters)
{
  return format(sql, dbType, parameters, (FormatOption_ptr) nullptr);
}

string_ptr SQLUtils::format(string_ptr sql, DbType_ptr dbType, Object_list_ptr parameters, FormatOption_ptr option)
{
  return format(sql, dbType, parameters, option, FORMAT_DEFAULT_FEATURES);
}

string_ptr SQLUtils::format(string_ptr sql, DbType_ptr dbType, Object_list_ptr parameters, FormatOption_ptr option, SQLParserFeature_list_ptr features)
{
  try
  {
    SQLStatementParser_ptr parser = SQLParserUtils::createSQLStatementParser(sql, dbType, features);
    SQLStatement_list_ptr statementList = parser->parseStatementList();
    return toSQLString(statementList, dbType, parameters, option);
  }
  catch (ParserException ex)
  {
    // LOG->warn("rowFormat error", ex);
    return sql;
  }
}

string_ptr SQLUtils::toSQLString(SQLStatement_list_ptr statementList, DbType_ptr dbType)
{
  Object_list_ptr tmp = std::make_shared<std::list<Object_ptr>>();
  return toSQLString(statementList, dbType, tmp);
}

string_ptr SQLUtils::toSQLString(SQLStatement_list_ptr statementList, DbType_ptr dbType, FormatOption_ptr option)
{
  Object_list_ptr tmp = std::make_shared<std::list<Object_ptr>>();
  return toSQLString(statementList, dbType, tmp, option);
}

string_ptr SQLUtils::toSQLString(SQLStatement_list_ptr statementList, DbType_ptr dbType, Object_list_ptr parameters)
{
  std::shared_ptr<std::map<std::string, string_ptr>> tmp = std::make_shared<std::map<std::string, string_ptr>>();
  return toSQLString(statementList, dbType, parameters, (FormatOption_ptr) nullptr, tmp);
}

string_ptr SQLUtils::toSQLString(SQLStatement_list_ptr statementList,
                                 DbType_ptr dbType,
                                 Object_list_ptr parameters,
                                 FormatOption_ptr option)
{
  std::shared_ptr<std::map<std::string, string_ptr>> tmp = std::shared_ptr<std::map<std::string, string_ptr>>();
  return toSQLString(statementList, dbType, parameters, option, tmp);
}

string_ptr SQLUtils::toSQLString(
    SQLStatement_list_ptr statementList,
    DbType_ptr dbType,
    Object_list_ptr parameters,
    FormatOption_ptr option,
    std::shared_ptr<std::map<std::string, string_ptr>> tableMapping)
{
  std::stringstream out;
  SQLASTOutputVisitor_ptr visitor = createFormatOutputVisitor(&out, statementList, dbType);
  if (parameters != nullptr)
  {
    visitor->setInputParameters(parameters);
  }

  if (option == nullptr)
  {
    option = DEFAULT_FORMAT_OPTION;
  }
  visitor->setFeatures(option->features);

  if (tableMapping != nullptr)
  {
    visitor->setTableMapping(tableMapping);
  }

  BOOL_ptr printStmtSeperator;
  if (DbType::sqlserver.name->c_str() == dbType->name->c_str())
  {
    printStmtSeperator = BOOL::FALSE;
  }
  else
  {
    if (DbType::oracle.name->c_str() != dbType->name->c_str())
    {
      printStmtSeperator = BOOL::TRUE;
    }
    else
    {
      printStmtSeperator = BOOL::FALSE;
    }
  }

  auto it_statementList = statementList->begin();
  for (int i = 0, size = statementList->size(); i < size; i++)
  {
    std::advance(it_statementList, i);
    SQLStatement_ptr stmt = *it_statementList;

    if (i > 0)
    {
      std::advance(it_statementList, i - 1);
      SQLStatement_ptr preStmt = *it_statementList;
      if (printStmtSeperator && !preStmt->isAfterSemi())
      {
        visitor->print(make_string_ptr(";"));
      }

      string_list_ptr comments = preStmt->getAfterCommentsDirect();
      if (comments != nullptr)
      {
        auto it_comments = comments->begin();
        for (int j = 0; j < comments->size(); ++j)
        {
          std::advance(it_comments, j);
          string_ptr comment = *it_comments;
          if (j != 0)
          {
            visitor->println();
          }
          visitor->printComment(comment);
        }
      }

      if (printStmtSeperator)
      {
        visitor->println();
      }

      if (!(instanceof <SQLStatement, SQLSetStatement>(stmt)))
      {
        visitor->println();
      }
    }

    stmt->accept(visitor);

    if (i == size - 1)
    {
      string_list_ptr comments = stmt->getAfterCommentsDirect();
      if (comments != nullptr)
      {
        auto it_comments = comments->begin();
        for (int j = 0; j < comments->size(); ++j)
        {
          std::advance(it_comments, j);
          string_ptr comment = *it_comments;
          if (j != 0)
          {
            visitor->println();
          }
          visitor->printComment(comment);
        }
      }
    }
  }

  return make_string_ptr(out.str());
}

SQLASTOutputVisitor_ptr SQLUtils::createOutputVisitor(std::stringstream *out, DbType_ptr dbType)
{
  SQLStatement_list_ptr tmp = std::make_shared<std::list<SQLStatement_ptr>>();
  return createFormatOutputVisitor(out, tmp, dbType);
}

SQLASTOutputVisitor_ptr SQLUtils::createFormatOutputVisitor(std::stringstream *out,
                                                            SQLStatement_list_ptr statementList,
                                                            DbType_ptr dbType)
{
  if (dbType == nullptr)
  {
    if (statementList != nullptr && statementList->size() > 0)
    {
      dbType = (*statementList->begin())->getDbType();
    }

    if (dbType == nullptr)
    {
      dbType = DbType_ptr(new DbType(&DbType::other));
    }
  }

  if (dbType->name->c_str() == DbType::oracle.name->c_str() ||
      dbType->name->c_str() == DbType::oceanbase_oracle.name->c_str())
  {
    if (statementList == nullptr || statementList->size() == 1)
    {
      return OracleOutputVisitor_ptr(new OracleOutputVisitor(out, BOOL::FALSE));
    }
    else
    {
      return OracleOutputVisitor_ptr(new OracleOutputVisitor(out, BOOL::TRUE));
    }
  }
  else if (dbType->name->c_str() == DbType::mysql.name->c_str() ||
           dbType->name->c_str() == DbType::mariadb.name->c_str() ||
           dbType->name->c_str() == DbType::tidb.name->c_str())
  {
    return MySqlOutputVisitor_ptr(new MySqlOutputVisitor(out));
  }
  else if (dbType->name->c_str() == DbType::postgresql.name->c_str())
  {
    //             return new PGOutputVisitor(out);
  }
  else if (dbType->name->c_str() == DbType::sqlserver.name->c_str() ||
           dbType->name->c_str() == DbType::jtds.name->c_str())
  {
    // return SQLServerOutputVisitor_ptr(new SQLServerOutputVisitor(out));
  }
  else if (dbType->name->c_str() == DbType::db2.name->c_str())
  {
    //             return new DB2OutputVisitor(out);
  }
  else if (dbType->name->c_str() == DbType::odps.name->c_str())
  {
    //             return new OdpsOutputVisitor(out);
  }
  else if (dbType->name->c_str() == DbType::h2.name->c_str())
  {
    //             return new H2OutputVisitor(out);
  }
  else if (dbType->name->c_str() == DbType::hive.name->c_str())
  {
    //             return new HiveOutputVisitor(out);
  }
  else if (dbType->name->c_str() == DbType::ads.name->c_str())
  {
    //             return new AdsOutputVisitor(out);
  }
  else if (dbType->name->c_str() == DbType::blink.name->c_str())
  {
    //             return new BlinkOutputVisitor(out);
  }
  else if (dbType->name->c_str() == DbType::antspark.name->c_str())
  {
    //             return new AntsparkOutputVisitor(out);
  }
  else if (dbType->name->c_str() == DbType::presto.name->c_str())
  {
    //             return new PrestoOutputVisitor(out);
  }
  else if (dbType->name->c_str() == DbType::clickhouse.name->c_str())
  {
    //             return new ClickhouseOutputVisitor(out);
  }
  else if (dbType->name->c_str() == DbType::oscar.name->c_str())
  {
    //             return new OscarOutputVisitor(out);
  }
  else if (dbType->name->c_str() == DbType::starrocks.name->c_str())
  {
    //             return new StarRocksOutputVisitor(out);
  }
  else
  {
    return SQLASTOutputVisitor_ptr(new SQLASTOutputVisitor(out, dbType));
  }
}

SchemaStatVisitor_ptr SQLUtils::createSchemaStatVisitor(SQLStatement_list_ptr statementList, DbType_ptr dbType)
{
  return createSchemaStatVisitor(dbType);
}

SchemaStatVisitor_ptr SQLUtils::createSchemaStatVisitor(DbType_ptr dbType)
{
  SchemaRepository_ptr repository = nullptr;
  return createSchemaStatVisitor(repository, dbType);
}

SchemaStatVisitor_ptr SQLUtils::createSchemaStatVisitor(SchemaRepository_ptr repository)
{
  return createSchemaStatVisitor(repository, repository->getDbType());
}

SchemaStatVisitor_ptr SQLUtils::createSchemaStatVisitor(SchemaRepository_ptr repository, DbType_ptr dbType)
{
  if (repository == nullptr)
  {
    repository = SchemaRepository_ptr(new SchemaRepository(dbType));
  }

  if (dbType == nullptr)
  {
    return SchemaStatVisitor_ptr(new SchemaStatVisitor(repository));
  }

  if (dbType->name->c_str() == DbType::oracle.name->c_str())
  {
    // return OracleSchemaStatVisitor_ptr(new OracleSchemaStatVisitor(repository));
  }
  else if (dbType->name->c_str() == DbType::mysql.name->c_str() ||
           dbType->name->c_str() == DbType::mariadb.name->c_str() ||
           dbType->name->c_str() == DbType::tidb.name->c_str() ||
           dbType->name->c_str() == DbType::elastic_search.name->c_str())
  {
    return MySqlSchemaStatVisitor_ptr(new MySqlSchemaStatVisitor(repository));
  }
  else if (dbType->name->c_str() == DbType::postgresql.name->c_str())
  {
    // return new PGSchemaStatVisitor(repository);
  }
  else if (dbType->name->c_str() == DbType::sqlserver.name->c_str() ||
           dbType->name->c_str() == DbType::jtds.name->c_str())
  {
    // return SQLServerSchemaStatVisitor_ptr(new SQLServerSchemaStatVisitor(repository));
  }
  else if (dbType->name->c_str() == DbType::db2.name->c_str())
  {
    // return new DB2SchemaStatVisitor(repository);
  }
  else if (dbType->name->c_str() == DbType::odps.name->c_str())
  {
    // return new OdpsSchemaStatVisitor(repository);
  }
  else if (dbType->name->c_str() == DbType::h2.name->c_str())
  {
    // return new H2SchemaStatVisitor(repository);
  }
  else if (dbType->name->c_str() == DbType::hive.name->c_str())
  {
    // return new HiveSchemaStatVisitor(repository);
  }
  else if (dbType->name->c_str() == DbType::antspark.name->c_str())
  {
    // return new AntsparkSchemaStatVisitor(repository);
  }
  else if (dbType->name->c_str() == DbType::clickhouse.name->c_str())
  {
    // return new ClickSchemaStatVisitor(repository);
  }
  else
  {
    return SchemaStatVisitor_ptr(new SchemaStatVisitor(repository));
  }
}

// std::list<SQLStatement_ptr > SQLUtils::parseStatements(string_ptr  sql, DbType_ptr   dbType, std::list<SQLParserFeature *> features)
// {
//   return parseStatements(sql, dbType, features);
// }

SQLStatement_list_ptr SQLUtils::parseStatements(
    string_ptr sql,
    DbType_ptr dbType,
    SQLParserFeature_list_ptr features)
{
  LOG_INFO << "goto createSQLStatementParser";
  SQLStatementParser_ptr parser = SQLParserUtils::createSQLStatementParser(sql, dbType, features);
  SQLStatement_list_ptr stmtList = std::make_shared<std::list<SQLStatement_ptr>>();

#ifdef TRY
  try
  {
#endif
    SQLObject_ptr obj = SQLObject_ptr(new SQLObject());
    LOG_INFO << "goto parseStatementList";
    parser->parseStatementList(stmtList, -1, obj);

    LOG_INFO << ": token name:" << parser->getLexer()->token()->getName()->c_str() << ": " << parser->getLexer()->stringVal()->c_str();
    if (parser->getLexer()->token()->name->c_str() != Token::XEOF.name->c_str())
    {
      std::string tmp = "syntax error : ";
      tmp += encode_util::UnicodeToUTF8(parser->getLexer()->info()).c_str();
      throw new ParserException(make_string_ptr(tmp));
    }
#ifdef TRY
  }
  catch (const std::exception &e)
  {
    LOG_INFO << "catch +++++++++++:" << e.what();
  }
  catch (...)
  {
    LOG_INFO << "catch +++++++++++:";
  }
#endif
  LOG_INFO << "stmtList.size:" << stmtList->size();
  return stmtList;
}

SQLStatement_list_ptr SQLUtils::parseStatements(
    string_ptr sql,
    DbType_ptr dbType,
    BOOL_ptr keepComments)
{
  SQLStatementParser_ptr parser = SQLParserUtils::createSQLStatementParser(sql, dbType, keepComments);
  SQLStatement_list_ptr stmtList = parser->parseStatementList();
  if (*parser->getLexer()->token() != Token::XEOF)
  {
    throw new ParserException(make_string_ptr("syntax error-> " + *sql));
  }
  // SQLStatement_list_ptr stmtList = std::make_shared<std::list<SQLStatement_ptr>>();
  return stmtList;
}

// std::list<SQLStatement_ptr > SQLUtils::parseStatements(string_ptr  sql, string_ptr  dbType)
// {
//   std::list<SQLParserFeature *> tmp ;
//   return parseStatements(sql, dbType, tmp);
// }

SQLStatement_list_ptr SQLUtils::parseStatements(string_ptr sql, DbType_ptr dbType)
{
  SQLParserFeature_list_ptr tmp = std::make_shared<std::list<SQLParserFeature_ptr>>();
  // LOG_INFO << "dbType:"<<dbType->name->c_str();
  return parseStatements(sql, dbType, tmp);
}

SQLStatement_ptr SQLUtils::parseSingleStatement(string_ptr sql, DbType_ptr dbType, BOOL_ptr keepComments)
{
  SQLStatementParser_ptr parser = SQLParserUtils::createSQLStatementParser(sql, dbType, keepComments);
  SQLStatement_list_ptr stmtList = parser->parseStatementList();

  if (stmtList->size() > 1)
  {
    throw new ParserException(make_string_ptr("multi-statement be found->"));
  }

  if (*parser->getLexer()->token() != Token::XEOF)
  {
    throw new ParserException(make_string_ptr("syntax error-> " + *sql));
  }
  auto it_stmtList = stmtList->begin();
  std::advance(it_stmtList, 0);
  return (*it_stmtList);
}

// SQLStatement_ptr SQLUtils::parseSingleStatement(string_ptr  sql, string_ptr  dbType, std::list<SQLParserFeature *> *features)
// {
//   return parseSingleStatement(sql, &DbType::valueOf(dbType), features);
// }

SQLStatement_ptr SQLUtils::parseSingleStatement(
    string_ptr sql,
    DbType_ptr dbType,
    SQLParserFeature_list_ptr features)
{
  SQLStatementParser_ptr parser = SQLParserUtils::createSQLStatementParser(sql, dbType, features);
  SQLStatement_list_ptr stmtList = parser->parseStatementList();

  if (stmtList->size() > 1)
  {
    throw new ParserException(make_string_ptr("multi-statement be found->"));
  }

  if (*parser->getLexer()->token() != Token::XEOF)
  {
    throw new ParserException(make_string_ptr("syntax error-> " + *sql));
  }
  auto it_stmtList = stmtList->begin();
  std::advance(it_stmtList, 0);
  return (*it_stmtList);
}

SQLStatement_ptr SQLUtils::parseSingleMysqlStatement(string_ptr sql)
{
  return parseSingleStatement(sql, DbType_ptr(new DbType(&DbType::mysql)), BOOL::FALSE);
}

/**
 * @param columnName
 * @param tableAlias
 * @param pattern    if pattern is nullptr,it will be set {%Y-%m-%d %H:%i:%s} as mysql default value and set {yyyy-mm-dd
 *                   hh24:mi:ss} as oracle default value
 * @param dbType     {@link DbType_ptr   } if dbType is nullptr ,it will be set the mysql as a default value
 * @author owenludong->lud
 */
string_ptr SQLUtils::buildToDate(string_ptr columnName, string_ptr tableAlias, string_ptr pattern, DbType_ptr dbType)
{
  string_ptr sql;
  if (columnName->empty())
  {
    return make_string_ptr("");
  }
  // if (dbType == nullptr)
  // {
  //   dbType = &DbType::mysql;
  // }
  string_ptr formatMethod = make_string_ptr("");
  // if (JdbcUtils::isMysqlDbType(dbType))
  // {
  //   formatMethod = "STR_TO_DATE";
  //   if (StringUtils::isEmpty(pattern))
  //   {
  //     pattern = "%Y-%m-%d %H:%i:%s";
  //   }
  // }
  // else if (&DbType::oracle == dbType)
  // {
  //   formatMethod = "TO_DATE";
  //   if (StringUtils::isEmpty(pattern))
  //   {
  //     pattern = "yyyy-mm-dd hh24:mi:ss";
  //   }
  // }
  // else
  // {
  //   return "";
  //   // expand date's handle method for other database
  // }
  sql->append(*formatMethod.get());
  sql->append("(");
  if (!tableAlias->empty())
  {
    sql->append(*tableAlias.get());
    sql->append("->");
  }
  sql->append(*columnName.get());
  sql->append(",");
  sql->append("'");
  sql->append(*pattern.get());
  sql->append("')");
  return sql;
}

SQLExpr_list_ptr SQLUtils::split(SQLBinaryOpExpr_ptr x)
{
  return SQLBinaryOpExpr::split(x);
}

string_ptr SQLUtils::translateOracleToMySql(string_ptr sql)
{
  SQLStatement_list_ptr stmtList = toStatementList(sql, DbType_ptr(new DbType(&DbType::oracle)));

  // StringBuilder *out = new StringBuilder *();
  string_ptr out;
  // OracleToMySqlOutputVisitor visitor = new OracleToMySqlOutputVisitor(out, BOOL::FALSE);
  for (int i = 0; i < stmtList->size(); ++i)
  {
    // stmtList->get(i)->accept(visitor);
  }

  string_ptr mysqlSql = out;
  return mysqlSql;
}

string_ptr SQLUtils::addCondition(string_ptr sql, string_ptr condition, DbType_ptr dbType)
{
  string_ptr result = addCondition(sql, condition, SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::BooleanAnd)), BOOL::FALSE, dbType);
  return result;
}

string_ptr SQLUtils::addCondition(string_ptr sql, string_ptr condition, SQLBinaryOperator_ptr op, BOOL_ptr left, DbType_ptr dbType)
{
  if (sql->empty())
  {
    throw new IllegalArgumentException(make_string_ptr("sql is nullptr"));
  }

  if (condition->empty())
  {
    return sql;
  }

  if (op == nullptr)
  {
    op = SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::BooleanAnd));
  }

  if (!(op->name->c_str() == SQLBinaryOperator::BooleanAnd.name->c_str()) //
      && !(op->name->c_str() == SQLBinaryOperator::BooleanOr.name->c_str()))
  {
    throw new IllegalArgumentException(make_string_ptr("add condition not support : " + *op->getName()));
  }

  SQLStatement_list_ptr stmtList = parseStatements(sql, dbType);

  if (stmtList->empty())
  {
    throw new IllegalArgumentException(make_string_ptr("not support empty-statement :" + *sql));
  }

  if (stmtList->size() > 1)
  {
    throw new IllegalArgumentException(make_string_ptr("not support multi-statement :" + *sql));
  }

  auto it_stmtList = stmtList->begin();
  std::advance(it_stmtList, 0);
  SQLStatement_ptr stmt = (*it_stmtList);

  SQLExpr_ptr conditionExpr = toSQLExpr(condition, dbType);

  addCondition(stmt, op, conditionExpr, left);

  return toSQLString(std::dynamic_pointer_cast<SQLObject>(stmt), dbType);
}

void SQLUtils::addCondition(SQLStatement_ptr stmt, SQLBinaryOperator_ptr op, SQLExpr_ptr condition, BOOL_ptr left)
{
  // if (instanceof<SQLStatement, SQLSelectStatement>(stmt)  )
  // {
  //   SQLSelectQuery *query = ((SQLSelectStatement)stmt)->getSelect()->getQuery();
  //   if (query instanceof SQLSelectQueryBlock *)
  //   {
  //     SQLSelectQueryBlock *queryBlock = (SQLSelectQueryBlock *)query;
  //     SQLExpr_ptr newCondition = buildCondition(op, condition, left, queryBlock->getWhere());
  //     queryBlock->setWhere(newCondition);
  //   }
  //   else
  //   {
  //     throw new IllegalArgumentException("add condition not support " + stmt->getClass()->getName());
  //   }

  //   return;
  // }

  // if (stmt instanceof SQLDeleteStatement)
  // {
  //   SQLDeleteStatement delete = (SQLDeleteStatement)stmt;

  //   SQLExpr_ptr newCondition = buildCondition(op, condition, left, delete->getWhere());
  //   delete->setWhere(newCondition);

  //   return;
  // }

  // if (stmt instanceof SQLUpdateStatement)
  // {
  //   SQLUpdateStatement update = (SQLUpdateStatement)stmt;

  //   SQLExpr_ptr newCondition = buildCondition(op, condition, left, update->getWhere());
  //   update->setWhere(newCondition);

  //   return;
  // }
  string_ptr tmp = make_string_ptr("add condition not support ");
  tmp->append((stmt->getClass())->c_str());
  throw new IllegalArgumentException(tmp);
}

SQLExpr_ptr SQLUtils::buildCondition(SQLBinaryOperator_ptr op, SQLExpr_ptr condition, BOOL_ptr left, SQLExpr_ptr where)
{
  if (where == nullptr)
  {
    return condition;
  }

  SQLBinaryOpExpr_ptr newCondition = nullptr;
  if (left)
  {
    newCondition = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(condition, op, where));
  }
  else
  {
    newCondition = SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(where, op, condition));
  }
  return newCondition;
}

string_ptr SQLUtils::addSelectItem(string_ptr selectSql, string_ptr expr, string_ptr alias, DbType_ptr dbType)
{
  return addSelectItem(selectSql, expr, alias, BOOL::FALSE, dbType);
}

// void SQLUtils::acceptBooleanOr(string_ptr  sql, DbType_ptr   dbType, Consumer<SQLBinaryOpExprGroup*> consumer)
// {
//   acceptBinaryOpExprGroup(sql, dbType, consumer, e->e->getOperator() == SQLBinaryOperator::BooleanOr);
// }

// void SQLUtils::acceptBinaryOpExprGroup(string_ptr  sql,
//                                        DbType_ptr   dbType,
//                                        Consumer<SQLBinaryOpExprGroup> consumer,
//                                        Predicate<SQLBinaryOpExprGroup> filter)
// {
//   if (sql == nullptr || sql->isEmpty())
//   {
//     return;
//   }

//   std::list<SQLStatement_ptr > stmtList = new ArrayList<>();

//   try
//   {
//     SQLStatementParser *parser = SQLParserUtils::createSQLStatementParser(sql, dbType, SQLParserFeature->EnableMultiUnion, SQLParserFeature->KeepComments, SQLParserFeature->EnableSQLBinaryOpExprGroup);
//     parser->parseStatementList(stmtList, -1, nullptr);
//   }
//   catch (Exception ignored)
//   {
//     return;
//   }

//   SQLASTVisitor *visitor;
//   switch (dbType)
//   {
//   case odps:
//     visitor = new OdpsASTVisitorAdapter(){

//         BOOL_ptr visit(SQLBinaryOpExprGroup x){
//             if (filter == nullptr || filter->test(x)){
//                 consumer->accept(x);
//   }
//   return super->visit(x);
// }
// }
// ;
// break;
// default:
// visitor = new SQLASTVisitorAdapter(){

//     BOOL_ptr visit(SQLBinaryOpExprGroup x){
//         if (filter == nullptr || filter->test(x)){
//             consumer->accept(x);
// }
// return super->visit(x);
// }
// }
// ;
// break;
// }

// for (SQLStatement_ptr stmt : stmtList)
// {
//   stmt->accept(visitor);
// }
// }

// void SQLUtils::acceptBinaryOpExpr(string_ptr  sql,
//                                   DbType_ptr   dbType,
//                                   Consumer<SQLBinaryOpExpr> consumer,
//                                   Predicate<SQLBinaryOpExpr> filter)
// {
//   if (sql == nullptr || sql->isEmpty())
//   {
//     return;
//   }

//   std::list<SQLStatement_ptr > stmtList = new ArrayList<>();

//   try
//   {
//     SQLStatementParser *parser = SQLParserUtils::createSQLStatementParser(sql, dbType, SQLParserFeature->EnableMultiUnion, SQLParserFeature->KeepComments, SQLParserFeature->EnableSQLBinaryOpExprGroup);
//     parser->parseStatementList(stmtList, -1, nullptr);
//   }
//   catch (Exception ignored)
//   {
//     return;
//   }

//   SQLASTVisitor *visitor;
//   switch (dbType)
//   {
//   case odps:
//     visitor = new OdpsASTVisitorAdapter(){

//         BOOL_ptr visit(SQLBinaryOpExpr x){
//             if (filter == nullptr || filter->test(x)){
//                 consumer->accept(x);
//   }
//   return super->visit(x);
// }
// }
// ;
// break;
// default:
// visitor = new SQLASTVisitorAdapter(){

//     BOOL_ptr visit(SQLBinaryOpExpr x){
//         if (filter == nullptr || filter->test(x)){
//             consumer->accept(x);
// }
// return super->visit(x);
// }
// }
// ;
// break;
// }

// for (SQLStatement_ptr stmt : stmtList)
// {
//   stmt->accept(visitor);
// }
// }

// void SQLUtils::acceptTableSource(string_ptr  sql,
//                                  DbType_ptr   dbType,
//                                  Consumer<SQLTableSource_ptr > consumer,
//                                  Predicate<SQLTableSource_ptr > filter)
// {
//   if (sql == nullptr || sql->isEmpty())
//   {
//     return;
//   }

//   std::list<SQLStatement_ptr > stmtList = new ArrayList<>();

//   try
//   {
//     SQLStatementParser *parser = SQLParserUtils::createSQLStatementParser(sql, dbType, SQLParserFeature->EnableMultiUnion, SQLParserFeature->KeepComments, SQLParserFeature->EnableSQLBinaryOpExprGroup);
//     parser->parseStatementList(stmtList, -1, nullptr);
//   }
//   catch (Exception ignored)
//   {
//     return;
//   }

//   SQLASTVisitor *visitor;
//   switch (dbType)
//   {
//   case odps:
//     visitor = new OdpsASTVisitorAdapter(){

//         BOOL_ptr visit(SQLExprTableSource x){
//             if (filter == nullptr || filter->test(x)){
//                 consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLJoinTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLSubqueryTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLUnionQueryTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLValuesTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLUnnestTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLWithSubqueryClause->Entry x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLLateralViewTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLAdhocTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }
// }
// ;
// break;
// case mysql:
// visitor = new MySqlASTVisitorAdapter(){
//     BOOL_ptr visit(SQLExprTableSource x){
//         if (filter == nullptr || filter->test(x)){
//             consumer->accept(x);
// }
// return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLJoinTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLSubqueryTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLUnionQueryTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLValuesTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLUnnestTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLWithSubqueryClause->Entry x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLLateralViewTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLAdhocTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(MySqlUpdateTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }
// }
// ;
// break;
// case oracle:
// visitor = new OracleASTVisitorAdapter(){
//     BOOL_ptr visit(SQLExprTableSource x){
//         if (filter == nullptr || filter->test(x)){
//             consumer->accept(x);
// }
// return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLSubqueryTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLJoinTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLUnionQueryTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLValuesTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLUnnestTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLWithSubqueryClause->Entry x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLLateralViewTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLAdhocTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(OracleSelectTableReference x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(OracleWithSubqueryEntry x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(OracleSelectSubqueryTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }
// }
// ;
// break;
// default:
// visitor = new SQLASTVisitorAdapter(){
//     BOOL_ptr visit(SQLExprTableSource x){
//         if (filter == nullptr || filter->test(x)){
//             consumer->accept(x);
// }
// return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLJoinTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLSubqueryTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLValuesTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLUnnestTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLUnionQueryTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLWithSubqueryClause->Entry x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLLateralViewTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLAdhocTableSource x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }
// }
// ;
// break;
// }

// for (SQLStatement_ptr stmt : stmtList)
// {
//   stmt->accept(visitor);
// }
// }

// void SQLUtils::acceptSelectQueryBlock(string_ptr  sql,
//                                       DbType_ptr   dbType,
//                                       Consumer<SQLSelectQueryBlock *> consumer,
//                                       Predicate<SQLSelectQueryBlock *> filter)
// {
//   if (sql == nullptr || sql->isEmpty())
//   {
//     return;
//   }

//   std::list<SQLStatement_ptr > stmtList = new ArrayList<>();

//   try
//   {
//     SQLStatementParser *parser = SQLParserUtils::createSQLStatementParser(sql, dbType, SQLParserFeature->EnableMultiUnion, SQLParserFeature->KeepComments, SQLParserFeature->EnableSQLBinaryOpExprGroup);
//     parser->parseStatementList(stmtList, -1, nullptr);
//   }
//   catch (Exception ignored)
//   {
//     return;
//   }

//   SQLASTVisitor *visitor;
//   switch (dbType)
//   {
//   case odps:
//     visitor = new OdpsASTVisitorAdapter(){

//         BOOL_ptr visit(SQLSelectQueryBlock * x){
//             if (filter == nullptr || filter->test(x)){
//                 consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(OdpsSelectQueryBlock x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }
// }
// ;
// break;
// case mysql:
// visitor = new MySqlASTVisitorAdapter(){

//     BOOL_ptr visit(SQLSelectQueryBlock * x){
//         if (filter == nullptr || filter->test(x)){
//             consumer->accept(x);
// }
// return BOOL::TRUE;
// }

// BOOL_ptr visit(MySqlSelectQueryBlock x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }
// }
// ;
// break;
// default:
// visitor = new SQLASTVisitorAdapter(){

//     BOOL_ptr visit(SQLSelectQueryBlock * x){
//         if (filter == nullptr || filter->test(x)){
//             consumer->accept(x);
// }
// return BOOL::TRUE;
// }
// }
// ;
// break;
// }

// for (SQLStatement_ptr stmt : stmtList)
// {
//   stmt->accept(visitor);
// }
// }

// void SQLUtils::acceptAggregateFunction(string_ptr  sql,
//                                        DbType_ptr   dbType,
//                                        Consumer<SQLAggregateExpr> consumer,
//                                        Predicate<SQLAggregateExpr> filter)
// {
//   if (sql == nullptr || sql->isEmpty())
//   {
//     return;
//   }

//   std::list<SQLStatement_ptr > stmtList = new ArrayList<>();

//   try
//   {
//     SQLStatementParser *parser = SQLParserUtils::createSQLStatementParser(sql, dbType, SQLParserFeature->EnableMultiUnion, SQLParserFeature->KeepComments, SQLParserFeature->EnableSQLBinaryOpExprGroup);
//     parser->parseStatementList(stmtList, -1, nullptr);
//   }
//   catch (Exception ignored)
//   {
//     return;
//   }

//   SQLASTVisitor *visitor;
//   switch (dbType)
//   {
//   case odps:
//     visitor = new OdpsASTVisitorAdapter(){

//         BOOL_ptr visit(SQLAggregateExpr x){
//             if (filter == nullptr || filter->test(x)){
//                 consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }
// }
// ;
// break;
// case mysql:
// visitor = new MySqlASTVisitorAdapter(){

//     BOOL_ptr visit(SQLAggregateExpr x){
//         if (filter == nullptr || filter->test(x)){
//             consumer->accept(x);
// }
// return BOOL::TRUE;
// }
// }
// ;
// break;
// case oracle:
// visitor = new OracleASTVisitorAdapter(){

//     BOOL_ptr visit(SQLAggregateExpr x){
//         if (filter == nullptr || filter->test(x)){
//             consumer->accept(x);
// }
// return BOOL::TRUE;
// }
// }
// ;
// break;
// default:
// visitor = new SQLASTVisitorAdapter(){

//     BOOL_ptr visit(SQLAggregateExpr x){
//         if (filter == nullptr || filter->test(x)){
//             consumer->accept(x);
// }
// return BOOL::TRUE;
// }
// }
// ;
// break;
// }

// for (SQLStatement_ptr stmt : stmtList)
// {
//   stmt->accept(visitor);
// }
// }

// void SQLUtils::acceptFunction(string_ptr  sql,
//                               DbType_ptr   dbType,
//                               Consumer<SQLMethodInvokeExpr> consumer,
//                               Predicate<SQLMethodInvokeExpr> filter)
// {
//   if (sql == nullptr || sql->isEmpty())
//   {
//     return;
//   }

//   std::list<SQLStatement_ptr > stmtList = new ArrayList<>();

//   try
//   {
//     SQLStatementParser *parser = SQLParserUtils::createSQLStatementParser(sql, dbType, SQLParserFeature->EnableMultiUnion, SQLParserFeature->KeepComments, SQLParserFeature->EnableSQLBinaryOpExprGroup);
//     parser->parseStatementList(stmtList, -1, nullptr);
//   }
//   catch (Exception ignored)
//   {
//     return;
//   }

//   SQLASTVisitor *visitor;
//   switch (dbType)
//   {
//   case odps:
//     visitor = new OdpsASTVisitorAdapter(){

//         BOOL_ptr visit(SQLMethodInvokeExpr x){
//             if (filter == nullptr || filter->test(x)){
//                 consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLAggregateExpr x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }
// }
// ;
// break;
// case mysql:
// visitor = new MySqlASTVisitorAdapter(){

//     BOOL_ptr visit(SQLMethodInvokeExpr x){
//         if (filter == nullptr || filter->test(x)){
//             consumer->accept(x);
// }
// return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLAggregateExpr x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }
// }
// ;
// break;
// case oracle:
// visitor = new OracleASTVisitorAdapter(){

//     BOOL_ptr visit(SQLMethodInvokeExpr x){
//         if (filter == nullptr || filter->test(x)){
//             consumer->accept(x);
// }
// return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLAggregateExpr x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }
// }
// ;
// break;
// default:
// visitor = new SQLASTVisitorAdapter(){

//     BOOL_ptr visit(SQLAggregateExpr x){
//         if (filter == nullptr || filter->test(x)){
//             consumer->accept(x);
// }
// return BOOL::TRUE;
// }

// BOOL_ptr visit(SQLMethodInvokeExpr x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }
// }
// ;
// break;
// }

// for (SQLStatement_ptr stmt : stmtList)
// {
//   stmt->accept(visitor);
// }
// }

// void SQLUtils::acceptInsertInto(string_ptr  sql,
//                                 DbType_ptr   dbType,
//                                 Consumer<SQLInsertInto> consumer,
//                                 Predicate<SQLInsertInto> filter)
// {
//   if (sql == nullptr || sql->isEmpty())
//   {
//     return;
//   }

//   std::list<SQLStatement_ptr > stmtList = new ArrayList<>();

//   try
//   {
//     SQLStatementParser *parser = SQLParserUtils::createSQLStatementParser(sql, dbType, SQLParserFeature->EnableMultiUnion, SQLParserFeature->KeepComments, SQLParserFeature->EnableSQLBinaryOpExprGroup);
//     parser->parseStatementList(stmtList, -1, nullptr);
//   }
//   catch (Exception ignored)
//   {
//     return;
//   }

//   SQLASTVisitor *visitor;
//   switch (dbType)
//   {
//   case odps:
//     visitor = new OdpsASTVisitorAdapter(){

//         BOOL_ptr visit(SQLSelectStatement x){
//             return BOOL::FALSE;
//   }

//   BOOL_ptr visit(SQLCreateTableStatement x)
//   {
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(HiveCreateTableStatement x)
//   {
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(OdpsCreateTableStatement x)
//   {
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(SQLSelectQueryBlock * x)
//   {
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(OdpsSelectQueryBlock x)
//   {
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(SQLInsertStatement * x)
//   {
//     if (filter == nullptr || filter->test(x))
//     {
//       consumer->accept(x);
//     }
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(HiveInsertStatement x)
//   {
//     if (filter == nullptr || filter->test(x))
//     {
//       consumer->accept(x);
//     }
//     return BOOL::FALSE;
//   }

//   BOOL_ptr visit(HiveInsert x)
//   {
//     if (filter == nullptr || filter->test(x))
//     {
//       consumer->accept(x);
//     }
//     return BOOL::FALSE;
//   }
// };
// break;
// case hive:
// visitor = new HiveASTVisitorAdapter(){

//     BOOL_ptr visit(SQLSelectStatement x){
//         return BOOL::FALSE;
// }

// BOOL_ptr visit(SQLCreateTableStatement x)
// {
//   return BOOL::FALSE;
// }

// BOOL_ptr visit(HiveCreateTableStatement x)
// {
//   return BOOL::FALSE;
// }

// BOOL_ptr visit(SQLInsertStatement *x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::FALSE;
// }

// BOOL_ptr visit(HiveInsertStatement x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::FALSE;
// }

// BOOL_ptr visit(HiveInsert x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::FALSE;
// }
// }
// ;
// break;
// default:
// visitor = new SQLASTVisitorAdapter(){

//     BOOL_ptr visit(SQLSelectStatement x){
//         return BOOL::FALSE;
// }

// BOOL_ptr visit(SQLCreateTableStatement x)
// {
//   return BOOL::FALSE;
// }

// BOOL_ptr visit(SQLInsertStatement *x)
// {
//   if (filter == nullptr || filter->test(x))
//   {
//     consumer->accept(x);
//   }
//   return BOOL::TRUE;
// }
// }
// ;
// break;
// }

// for (SQLStatement_ptr stmt : stmtList)
// {
//   stmt->accept(visitor);
// }
// }

string_ptr SQLUtils::addSelectItem(string_ptr selectSql, string_ptr expr, string_ptr alias, BOOL_ptr first, DbType_ptr dbType)
{
  SQLStatement_list_ptr stmtList = parseStatements(selectSql, dbType);

  if (stmtList->empty())
  {
    throw new IllegalArgumentException(make_string_ptr("not support empty-statement :" + *selectSql));
  }

  if (stmtList->size() > 1)
  {
    throw new IllegalArgumentException(make_string_ptr("not support multi-statement :" + *selectSql));
  }

  auto it_stmtList = stmtList->begin();
  std::advance(it_stmtList, 0);
  SQLStatement_ptr stmt = (*it_stmtList);

  SQLExpr_ptr columnExpr = toSQLExpr(expr, dbType);

  addSelectItem(stmt, columnExpr, alias, first);

  return toSQLString(std::dynamic_pointer_cast<SQLObject>(stmt), dbType);
}

void SQLUtils::addSelectItem(SQLStatement_ptr stmt, SQLExpr_ptr expr, string_ptr alias, BOOL_ptr first)
{
  if (expr == nullptr)
  {
    return;
  }

  // if (stmt instanceof SQLSelectStatement)
  // {
  //   SQLSelectQuery *query = ((SQLSelectStatement)stmt)->getSelect()->getQuery();
  //   if (query instanceof SQLSelectQueryBlock *)
  //   {
  //     SQLSelectQueryBlock *queryBlock = (SQLSelectQueryBlock *)query;
  //     addSelectItem(queryBlock, expr, alias, first);
  //   }
  //   else
  //   {
  //     throw new IllegalArgumentException("add condition not support " + stmt->getClass()->getName());
  //   }

  //   return;
  // }
  string_ptr tmp = make_string_ptr("add selectItem not support ");
  tmp->append(stmt->getClass()->c_str());
  throw new IllegalArgumentException(tmp);
}

void SQLUtils::addSelectItem(SQLSelectQueryBlock_ptr queryBlock, SQLExpr_ptr expr, string_ptr alias, BOOL_ptr first)
{
  SQLSelectItem_ptr selectItem = SQLSelectItem_ptr(new SQLSelectItem(expr, alias));
  queryBlock->getSelectList()->push_back(selectItem);
  selectItem->setParent(selectItem);
}

string_ptr SQLUtils::refactor(string_ptr sql, DbType_ptr dbType, std::shared_ptr<std::map<std::string, string_ptr>> tableMapping)
{
  SQLStatement_list_ptr stmtList = parseStatements(sql, dbType);
  Object_list_ptr tmp = std::make_shared<std::list<Object_ptr>>();
  return SQLUtils::toSQLString(stmtList, dbType, tmp, (FormatOption_ptr) nullptr, tableMapping);
}

long SQLUtils::hash(string_ptr sql, DbType_ptr dbType)
{
  Lexer_ptr lexer = SQLParserUtils::createLexer(sql, dbType);

  // StringBuilder *buf = new StringBuilder *(sql->length());
  string_ptr buf;

  for (;;)
  {
    lexer->nextToken();

    Token_ptr token = lexer->token();
    if (*token == Token::XEOF)
    {
      break;
    }

    if (*token == Token::ERROR)
    {
      return Utils::fnv_64(sql);
    }

    if (buf->length() != 0)
    {
      // skip
    }
  }

  // return buf->hashCode();
  return 1;
}

SQLExpr_ptr SQLUtils::not_(SQLExpr_ptr expr)
{
  if (instanceof <SQLExpr, SQLBinaryOpExpr>(expr))
  {
    SQLBinaryOpExpr_ptr binaryOpExpr = std::dynamic_pointer_cast<SQLBinaryOpExpr>(expr);
    SQLBinaryOperator_ptr op = binaryOpExpr->getOperator();

    SQLBinaryOperator_ptr notOp = nullptr;

    if (op->name == SQLBinaryOperator::Equality.name)
    {
      notOp = SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::LessThanOrGreater));
    }
    else if (op->name == SQLBinaryOperator::LessThanOrEqualOrGreaterThan.name)
    {
      notOp = SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Equality));
    }
    else if (op->name == SQLBinaryOperator::LessThan.name)
    {
      notOp = SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::GreaterThanOrEqual));
    }
    else if (op->name == SQLBinaryOperator::LessThanOrEqual.name)
    {
      notOp = SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::GreaterThan));
    }
    else if (op->name == SQLBinaryOperator::GreaterThan.name)
    {
      notOp = SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::LessThanOrEqual));
    }
    else if (op->name == SQLBinaryOperator::GreaterThanOrEqual.name)
    {
      notOp = SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::LessThan));
    }
    else if (op->name == SQLBinaryOperator::Is.name)
    {
      notOp = SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::IsNot));
    }
    else if (op->name == SQLBinaryOperator::IsNot.name)
    {
      notOp = SQLBinaryOperator_ptr(new SQLBinaryOperator(&SQLBinaryOperator::Is));
    }

    if (notOp != nullptr)
    {
      return SQLBinaryOpExpr_ptr(new SQLBinaryOpExpr(binaryOpExpr->getLeft(), notOp, binaryOpExpr->getRight()));
    }
  }

  if (instanceof <SQLExpr, SQLInListExpr>(expr))
  {
    SQLInListExpr_ptr inListExpr = std::dynamic_pointer_cast<SQLInListExpr>(expr);

    SQLInListExpr_ptr newInListExpr = SQLInListExpr_ptr(new SQLInListExpr(inListExpr));
    newInListExpr->getTargetList()->splice(newInListExpr->getTargetList()->end(), *inListExpr->getTargetList());
    // newInListExpr->setNot(!inListExpr->isNot());
    if (inListExpr->isNot() == BOOL::TRUE)
    {
      newInListExpr->setNot(BOOL::FALSE);
    }
    else
    {
      newInListExpr->setNot(BOOL::TRUE);
    }
    return newInListExpr;
  }

  return SQLUnaryExpr_ptr(new SQLUnaryExpr(SQLUnaryOperator_ptr(new SQLUnaryOperator(&SQLUnaryOperator::Not)), expr));
}

// string_ptr SQLUtils::normalize(string_ptr name)
// {
//   DbType_ptr tmp = DbType_ptr(new DbType());
//   return normalize(name, tmp);
// }

string_ptr SQLUtils::normalize(string_ptr name)
{
  DbType_ptr tmp = DbType_ptr(new DbType());
  return normalize(name, tmp);
}

string_ptr SQLUtils::normalize(string_ptr name, BOOL_ptr isTrimmed)
{
  string_ptr tmp = _normalize(name, DbType_ptr(new DbType(&DbType::other)), BOOL::FALSE, isTrimmed);
  return tmp;
}

// string_ptr SQLUtils::normalize(string_ptr name, DbType_ptr dbType)
// {
//   return _normalize(make_string_ptr(name), dbType, BOOL::FALSE);
// }

string_ptr SQLUtils::normalize(string_ptr name, DbType_ptr dbType)
{
  return _normalize(name, dbType, BOOL::FALSE);
}

string_ptr SQLUtils::_normalize(string_ptr name, DbType_ptr dbType, BOOL_ptr isForced)
{
  return _normalize(name, dbType, isForced, BOOL::TRUE);
}

string_ptr SQLUtils::_normalize(string_ptr name, DbType_ptr dbType, BOOL_ptr isForced, BOOL_ptr isTrimmed)
{
  if (name->empty())
  {
    return nullptr;
  }

  if (name->length() > 2)
  {
    char c0 = name->at(0);
    char x0 = name->at(name->length() - 1);
    if ((c0 == '[' && x0 == ']') ||
     (c0 == '"' && x0 == '"') || 
     (c0 == '`' && x0 == '`') || 
     (c0 == '\'' && x0 == '\''))
    {
      string_ptr normalizeName = make_string_ptr(name->substr(1, name->length() - 1));

      if (isTrimmed)
      {
        normalizeName = StringUtils::Trim(normalizeName);
      }

      int dotIndex = normalizeName->find("->");
      if (dotIndex > 0)
      {
        if (c0 == '`')
        {
          // boost::replace_all(*normalizeName, "`\\->`", "->");
          normalizeName = StringUtils::replaceAll(normalizeName, make_string_ptr("`\\->`"), make_string_ptr("->"));
        }
      }

      if (!isForced)
      {
        // if (&DbType::oracle == dbType)
        // {
        //   if (OracleUtils::isKeyword(normalizeName))
        //   {
        //     return name;
        //   }
        // }
        // else if (JdbcUtils::isMysqlDbType(dbType))
        // {
        //   if (MySqlUtils::isKeyword(normalizeName))
        //   {
        //     return name;
        //   }
        // }
        // else if (&DbType::postgresql == dbType || &DbType::db2 == dbType)
        // {
        //   if (PGUtils::isKeyword(normalizeName))
        //   {
        //     return name;
        //   }
        // }
      }

      return normalizeName;
    }
  }

  return name;
}

string_ptr SQLUtils::forcedNormalize(string_ptr name, DbType_ptr dbType)
{
  return _normalize(name, dbType, BOOL::TRUE);
}

bool SQLUtils::nameEquals(SQLName_ptr a, SQLName_ptr b)
{
  if (a == b)
  {
    return true;
  }

  if (a == nullptr || b == nullptr)
  {
    return false;
  }

  return a->nameHashCode64() == b->nameHashCode64();
}

// BOOL_ptr SQLUtils::nameEquals(string_ptr a, string_ptr b)
// {
//   if (a == b)
//   {
//     return BOOL::TRUE;
//   }

//   if (a->empty() || b->empty())
//   {
//     return BOOL::FALSE;
//   }

//   if (StringUtils::iequals(a, b))
//   {
//     return BOOL::TRUE;
//   }

//   string_ptr normalize_a = normalize(a);
//   string_ptr normalize_b = normalize(b);

//   return StringUtils::iequals(normalize_a, normalize_b);
// }

bool SQLUtils::nameEquals(string_ptr a, string_ptr b)
{
  if (a == b)
  {
    return true;
  }

  if (a->empty() || b->empty())
  {
    return false;
  }

  if (StringUtils::equalsIgnoreCase(a, b))
  {
    return true;
  }

  string_ptr normalize_a = normalize(a);
  string_ptr normalize_b = normalize(b);

  return StringUtils::equalsIgnoreCase(normalize_a, normalize_b);
}

BOOL_ptr SQLUtils::isValue(SQLExpr_ptr expr)
{
  if (instanceof <SQLExpr, SQLLiteralExpr>(expr))
  {
    return BOOL::TRUE;
  }

  if (instanceof <SQLExpr, SQLVariantRefExpr>(expr))
  {
    return BOOL::TRUE;
  }

  if (instanceof <SQLExpr, SQLBinaryOpExpr>(expr))
  {
    SQLBinaryOpExpr_ptr binaryOpExpr = std::dynamic_pointer_cast<SQLBinaryOpExpr>(expr);
    SQLBinaryOperator_ptr op = binaryOpExpr->getOperator();
    if (op->name->c_str() == SQLBinaryOperator::Add.name->c_str() || 
        op->name->c_str() == SQLBinaryOperator::Subtract.name->c_str() || 
        op->name->c_str() == SQLBinaryOperator::Multiply.name->c_str())
    {
      if (isValue(binaryOpExpr->getLeft()) == BOOL::TRUE &&
          isValue(binaryOpExpr->getRight()) == BOOL::TRUE)
      {
        return BOOL::TRUE;
      }
      else
      {
        BOOL::FALSE;
      }
    }
  }

  return BOOL::FALSE;
}

BOOL_ptr SQLUtils::replaceInParent(SQLExpr_ptr expr, SQLExpr_ptr target)
{
  if (expr == nullptr)
  {
    return BOOL::FALSE;
  }

  SQLObject_ptr parent = expr->getParent();

  if (instanceof <SQLObject, SQLReplaceable>(parent))
  {
    return (std::dynamic_pointer_cast<SQLReplaceable>(parent))->replace(expr, target);
  }

  return BOOL::FALSE;
}

BOOL_ptr SQLUtils::replaceInParent(SQLTableSource_ptr cmp, SQLTableSource_ptr dest)
{
  if (cmp == nullptr)
  {
    return BOOL::FALSE;
  }

  SQLObject_ptr parent = cmp->getParent();

  if (instanceof <SQLObject, SQLSelectQueryBlock>(parent))
  {
    SQLSelectQueryBlock_ptr queryBlock = std::dynamic_pointer_cast<SQLSelectQueryBlock>(parent);
    if (queryBlock->getFrom() == cmp)
    {
      queryBlock->setFrom(dest);
      return BOOL::TRUE;
    }
  }

  if (instanceof <SQLObject, SQLJoinTableSource>(parent))
  {
    SQLJoinTableSource_ptr join = std::dynamic_pointer_cast<SQLJoinTableSource>(parent);
    return join->replace(cmp, dest);
  }

  return BOOL::FALSE;
}

BOOL_ptr SQLUtils::replaceInParent(SQLSelectQuery_ptr cmp, SQLSelectQuery_ptr dest)
{
  if (cmp == nullptr)
  {
    return BOOL::FALSE;
  }

  SQLObject_ptr parent = cmp->getParent();
  if (parent == nullptr)
  {
    return BOOL::FALSE;
  }

  if (instanceof <SQLObject, SQLUnionQuery>(parent))
  {
    return (std::dynamic_pointer_cast<SQLUnionQuery>(parent))->replace(cmp, dest);
  }

  if (instanceof <SQLObject, SQLSelect>(parent))
  {
    return (std::dynamic_pointer_cast<SQLSelect>(parent))->replace(cmp, dest);
  }
  return BOOL::FALSE;
}

string_ptr SQLUtils::desensitizeTable(string_ptr tableName)
{
  if (tableName->empty())
  {
    return nullptr;
  }

  tableName = normalize(tableName);
  long hash = FnvHash::hashCode64(tableName);
  return Utils::hex_t(hash);
}

/**
 * 重新排序建表语句，解决建表语句的依赖关系
 *
 * @param sql
 * @param dbType
 */
string_ptr SQLUtils::sort(string_ptr sql, DbType_ptr dbType)
{
  SQLStatement_list_ptr stmtList = SQLUtils::parseStatements(sql, DbType_ptr(new DbType(&DbType::oracle)));

  SQLStatement_list_ptr tmp = SQLStatement_list_ptr();
  for (auto it : *stmtList)
  {
    tmp->push_back(it);
  }

  SQLCreateTableStatement::sort(tmp);
  return SQLUtils::toSQLString(stmtList, dbType);
}

/**
 * @param query
 * @param dbType
 * @return 0：sql->toString, 1:
 */
// std::list<Object_ptr > SQLUtils::clearLimit(string_ptr  query, DbType_ptr   dbType)
// {
//   std::list<SQLStatement_ptr > stmtList = SQLUtils::parseStatements(query, dbType);

//   SQLLimit *limit = nullptr;

//   auto it_stmtList = stmtList.begin();
//   std::advance(it_stmtList, 0);
//   SQLStatement_ptr statement = dynamic_cast<SQLStatement_ptr >((*it_stmtList));

//   // if (instanceof<SQLStatement, SQLSelectStatement>(statement)  )
//   // {
//   //   SQLSelectStatement* selectStatement = dynamic_cast<SQLSelectStatement*>(statement);

//   //   if (selectStatement->getSelect()->getQuery() instanceof SQLSelectQueryBlock *)
//   //   {
//   //     limit = clearLimit(selectStatement->getSelect()->getQueryBlock());
//   //   }
//   // }

//   // if (statement instanceof SQLDumpStatement)
//   // {
//   //   SQLDumpStatement dumpStatement = (SQLDumpStatement)statement;

//   //   if (dumpStatement->getSelect()->getQuery() instanceof SQLSelectQueryBlock *)
//   //   {
//   //     limit = clearLimit(dumpStatement->getSelect()->getQueryBlock());
//   //   }
//   // }

//   // if (statement instanceof MySqlSelectIntoStatement)
//   // {
//   //   MySqlSelectIntoStatement sqlSelectIntoStatement = (MySqlSelectIntoStatement)statement;
//   //   limit = clearLimit(sqlSelectIntoStatement->getSelect()->getQueryBlock());
//   // }

//   // if (statement instanceof MySqlInsertStatement)
//   // {
//   //   MySqlInsertStatement insertStatement = (MySqlInsertStatement)statement;
//   //   limit = clearLimit(insertStatement->getQuery()->getQueryBlock());
//   // }

//   string_ptr  sql = SQLUtils::toSQLString(stmtList, dbType);
//   return new Object[]{sql, limit};
// }

SQLLimit_ptr SQLUtils::clearLimit(SQLSelectQueryBlock_ptr queryBlock)
{
  if (queryBlock == nullptr)
  {
    return nullptr;
  }

  SQLLimit_ptr limit = queryBlock->getLimit();
  queryBlock->setLimit(nullptr);
  return limit;
}

SQLLimit_ptr SQLUtils::getLimit(SQLStatement_ptr statement, DbType_ptr dbType)
{
  if (instanceof <SQLStatement, SQLSelectStatement>(statement))
  {
    SQLSelectQueryBlock_ptr queryBlock = (std::dynamic_pointer_cast<SQLSelectStatement>(statement))->getSelect()->getQueryBlock();
    return queryBlock == nullptr ? nullptr : queryBlock->getLimit();
  }
  else if (instanceof <SQLStatement, SQLDumpStatement>(statement))
  {
    SQLSelectQueryBlock_ptr queryBlock = (std::dynamic_pointer_cast<SQLDumpStatement>(statement))->getSelect()->getQueryBlock();
    return queryBlock == nullptr ? nullptr : queryBlock->getLimit();
  }
  else if (instanceof <SQLStatement, MySqlSelectIntoStatement>(statement))
  {
    SQLSelectQueryBlock_ptr queryBlock = (std::dynamic_pointer_cast<MySqlSelectIntoStatement>(statement))->getSelect()->getQueryBlock();
    return queryBlock == nullptr ? nullptr : queryBlock->getLimit();
  }
  else if (instanceof <SQLStatement, MySqlInsertStatement>(statement))
  {
    SQLSelect_ptr select = (std::dynamic_pointer_cast<MySqlInsertStatement>(statement))->getQuery();

    if (select == nullptr)
    {
      return nullptr;
    }

    if (instanceof <SQLSelectQuery, SQLUnionQuery>(select->getQuery()))
    {
      return (std::dynamic_pointer_cast<SQLUnionQuery>(select->getQuery()))->getLimit();
    }
    else
    {
      return select->getQueryBlock()->getLimit();
    }
  }
  else
  {
    return nullptr;
  }
}

SQLLimit_ptr SQLUtils::getLimit(string_ptr query, DbType_ptr dbType)
{
  SQLStatement_list_ptr stmtList = SQLUtils::parseStatements(query, dbType);
  auto it_stmtList = stmtList->begin();
  std::advance(it_stmtList, 0);
  SQLStatement_ptr statement = (*it_stmtList);
  return getLimit(statement, dbType);
}

// string_ptr  SQLUtils::convertTimeZone(string_ptr  sql, TimeZone from, TimeZone to)
// {
//   SQLStatement_ptr statement = parseSingleMysqlStatement(sql);
//   statement->accept(new TimeZoneVisitor(from, to));
//   return statement->toString();
// }

// SQLStatement_ptr SQLUtils::convertTimeZone(SQLStatement_ptr stmt, TimeZone from, TimeZone to)
// {
//   stmt->accept(new TimeZoneVisitor(from, to));
//   return stmt;
// }

// std::list<SQLInsertStatement *> SQLUtils::splitInsertValues(DbType_ptr   dbType, string_ptr  insertSql, int size)
// {
//   SQLStatement_ptr statement = SQLUtils->parseStatements(insertSql, dbType, BOOL::FALSE)->get(0);
//   if (!(statement instanceof SQLInsertStatement *))
//   {
//     throw new IllegalArgumentException("The SQL must be insert statement->");
//   }

//   std::list<SQLInsertStatement *> insertLists = new ArrayList<SQLInsertStatement *>();

//   SQLInsertStatement *insertStatement = (SQLInsertStatement *)statement;

//   std::list<SQLInsertStatement *->ValuesClause> valuesList = insertStatement->getValuesList();

//   int totalSize = valuesList->size();
//   if (totalSize <= size)
//   {
//     insertLists->add(insertStatement);
//   }
//   else
//   {
//     SQLInsertStatement *insertTemplate = new SQLInsertStatement *();

//     insertStatement->cloneTo(insertTemplate);
//     insertTemplate->getValuesList()->clear();

//     int batchCount = 0;
//     if (totalSize % size == 0)
//     {
//       batchCount = totalSize / size;
//     }
//     else
//     {
//       batchCount = (totalSize / size) + 1;
//     }
//     for (int i = 0; i < batchCount; i++)
//     {
//       SQLInsertStatement *subInsertStatement = new SQLInsertStatement *();
//       insertTemplate->cloneTo(subInsertStatement);

//       int fromIndex = i * size;
//       int toIndex = (fromIndex + size) > totalSize ? totalSize : fromIndex + size;
//       std::list<SQLInsertStatement *->ValuesClause> subValuesList = valuesList->subList(fromIndex, toIndex);
//       subInsertStatement->getValuesList()->addAll(subValuesList);

//       insertLists->add(subInsertStatement);
//     }
//   }

//   return insertLists;
// }
